home *** CD-ROM | disk | FTP | other *** search
- {
- If you are designing a new Delphi control and you need to catch
- or limit changes to Left, Top, Width, or Height, there is one
- simple way to do it. However, I have yet to see the slightest
- hint of how to do it in the Delphi documentation (including
- the CWG).
-
- The key to catching changes to Left, Top, Width, Height, and
- even BoundsRect in Delphi is the SetBounds() method (found
- in TControl and all descendants). SetBounds() is a virtual
- function used to set the position and size of a control
- all in one easy step. However, what they do not tell you
- in the documentation is that TControl.SetBounds() is called
- by TControl's SetLeft(), SetTop(), SetWidth(), and SetHeight()
- property access methods every time a value is assigned to
- the Left, Top, Width, Height, and BoundsRect properties.
-
- Thus, to catch changes to these properties, simply override
- the SetBounds() method, do whatever you need with the new
- values, and then pass them on to the inherited SetBounds()
- method.
-
- In the following example, I have a control that automatically
- updates its X & Y custom properties to refer to the center
- of the control whenever Left, Top, Width, Height, or BoundsRect
- are changed. Conversely, Left and Top will be updated whenever
- X & Y are changed: }
-
- type
- TMyControl = class(TControl)
- private
- FX, FY : integer;
- {property access methods}
- procedure SetX(value : integer);
- procedure SetY(value : integer);
- ...
- public
- procedure SetBounds(aLeft, aTop, aWidth, aHeight : integer); override;
- ...
- property X : integer read FX write SetX;
- property Y : integer read FY write SetY;
- end;
- ...
-
- procedure TMyControl.SetX(value : integer);
- begin
- if FX <> value then
- SetBounds(value - Width div 2, Top, Width, Height);
- end;
-
- procedure TMyControl.SetY(value : integer);
- begin
- if FY <> value then
- SetBounds(Left, value - Height div 2, Width, Height);
- end;
-
- procedure TMyControl.SetBounds(aLeft, aTop, aWidth, aHeight : integer);
- begin
- {Go ahead and let SetBounds() do its thing...}
- inherited SetBounds(aLeft, aTop, aWidth, aHeight);
- {Now adjust FX and FY according to our new bounds.}
- FX := Width div 2;
- FY := Height div 2;
- end;
-
- Also not mentioned in the documentation is the fact that the
- FLeft, FTop, FWidth, and FHeight private fields that TControl
- uses to keep track of its bounding rectangle are not updated
- in the corresponding SetLeft(), SetTop(), etc. property access
- methods. These variables, in fact, do not get updated anywhere
- except in TControl's SetBounds() method (as with FX and FY in
- the above example).
-
- So, to limit changes to the bounds of your control, you can
- override SetBounds() to check and modify any of the properties
- before passing the values on to the inherited SetBounds()
- method.
-
- In the following example, I have a control that limits its
- width and height to no more than 100 pixels:
-
- type
- TMyControl = class(TControl)
- ...
- public
- procedure SetBounds(aLeft, aTop, aWidth, aHeight : integer); override;
- ...
- end;
-
- ...
- procedure TMyControl.SetBounds(aLeft, aTop, aWidth, aHeight : integer);
- begin
- if aWidth > 100 then
- aWidth := 100;
- if aHeight > 100 then
- aHeight := 100;
- inherited SetBounds(aLeft, aTop, aWidth, aHeight);
- end;